package whsw;

import whsw.tool.AssertParser;
import whsw.tool.ErrorMsg;
import whsw.tool.TableInfo;
import whsw.tool.TextTable;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 步骤四: 编写所有功能的业务逻辑, 包括增 删 改 查, 并收集到一起
 *
 * @author flutterdash@qq.com
 * @since 2021/6/20 13:41
 */
public class Handlers {

    /**
     * 提供一个工厂方法, 收集所有命令行处理器的实现
     * 策略工厂模式
     *
     * @return 策略工厂
     */
    public static Map<String, CommandLineHandler> getHandlers() {
        Map<String, CommandLineHandler> map = new HashMap<>();

        map.put("insert", new InsertAct()); // 增
        map.put("remove", new RemoveAct()); // 删
        map.put("update", new UpdateAct()); // 改
        map.put("select", new SelectAct()); // 查

        map.put("help", new HelpAct(map));  // 帮助信息

        return map;
    }

    public static class HelpAct implements CommandLineHandler {
        final Map<String, CommandLineHandler> handlers;
        public HelpAct(Map<String, CommandLineHandler> handlers) {
            this.handlers = handlers;
        }

        @Override
        public void handle(String command, Employees employees) {
            LinkedList<String> segments = toList(command);
            if (segments.isEmpty()) {
                CommandLineHandler.println("\n系统中可用的命令有 " + handlers.size() + " 个.");
                for (String key : handlers.keySet())
                    CommandLineHandler.println(key);
                CommandLineHandler.println("");
            } else {
                String act = segments.removeFirst();
                CommandLineHandler handler = handlers.get(act);
                if (handler == null)
                    throw new RuntimeException("系统中没有这个功能 `" + act + "`");
                CommandLineHandler.println(handler.help());
            }
        }

        @Override
        public String help() {
            return
                    "\n查看功能的帮助信息\n" +
                    "有两种用法\n" +
                    "仅输入 help , 会展示系统中所有可用的功能\n" +
                    "输入 help 功能 , 则展示此功能的使用帮助\n" +
                    "示例: 查看 update 这个功能的用法\n" +
                    "      help update\n";
        }
    }

    public static class InsertAct implements CommandLineHandler {
        @Override
        public void handle(String command, Employees employees) {
            LinkedList<String> segments = toList(command);
            if (segments.size() < 4)
                throw new RuntimeException("填写信息不完整");

            Employee newEmployee = new Employee();
            newEmployee.id = AssertParser.parserInt(segments.removeFirst(), ErrorMsg.errId);
            newEmployee.name = segments.removeFirst();
            newEmployee.sex = AssertParser.parserSex(segments.removeFirst(), ErrorMsg.errSex);
            newEmployee.age = AssertParser.parserInt(segments.removeFirst(), ErrorMsg.errAge);

            boolean flag = employees.insert(newEmployee);
            if (flag) {
                CommandLineHandler.println("插入成功");
            } else {
                CommandLineHandler.println("插入失败, 系统中已存在编号为 `" + newEmployee.id + "` 的员工信息");
            }
        }

        @Override
        public String help() {
            return
                    "\n插入一个员工信息\n" +
                    "      insert 编号 姓名 性别 年龄\n" +
                    "示例: 插入一条员工信息, 编号为1009, 姓名为XiaoMing, 性别为m, 年龄为21\n" +
                    "      insert 1009 XiaoMing m 21\n";
        }
    }

    public static class RemoveAct implements CommandLineHandler {
        @Override
        public void handle(String command, Employees employees) {
            LinkedList<String> segments = toList(command);
            if (segments.size() < 1)
                throw new RuntimeException("请同时输入要删除员工信息的编号");

            int id = AssertParser.parserInt(segments.removeFirst(), ErrorMsg.errId);
            boolean result = employees.remove(id);

            if (result)
                CommandLineHandler.println("删除成功");
            else
                CommandLineHandler.println("删除失败, 编号为 `" + id + "` 的员工信息不存在");
        }

        @Override
        public String help() {
            return
                    "\n删除某个员工\n" +
                    "      remove 员工编号\n" +
                    "示例: 删除编号为 1001 的员工信息\n" +
                    "      remove 1001\n";
        }
    }

    public static class UpdateAct implements CommandLineHandler {
        @Override
        public void handle(String command, Employees employees) {
            LinkedList<String> segments = toList(command);
            if (segments.size() < 3)
                throw new RuntimeException("缺少信息, 输入 help update 查看这个功能的使用帮助");

            int id = AssertParser.parserInt(segments.removeFirst(), ErrorMsg.errId);
            Employee theEmployee = employees.select(id);
            if (theEmployee == null)
                throw new RuntimeException("要修改员工信息, 但编号为 `" + id + "` 的员工不存在");

            String property = segments.removeFirst();
            switch (property) {
                case "姓名":
                    theEmployee.name = segments.removeFirst();
                    break;
                case "性别":
                    theEmployee.sex = AssertParser.parserSex(segments.removeFirst(), ErrorMsg.errSex);
                    break;
                case "年龄":
                    theEmployee.age = AssertParser.parserInt(segments.removeFirst(), ErrorMsg.errAge);
                    break;
                default:
                    throw new RuntimeException("修改失败, 未知属性 `" + property + "`");
            }
            CommandLineHandler.println("修改成功");
        }

        @Override
        public String help() {
            return
                    "\n修改一个员工的某个信息\n" +
                    "      update 员工编号 要修改的信息 修改后的值\n" +
                    "示例: 修改员工编号为 1001 的员工的姓名为 ZhangSan\n" +
                    "      update 1001 姓名 ZhangSan\n" +
                    "示例: 修改员工编号为 2002 的员工的年龄为 19\n" +
                    "      update 1001 年龄 19\n" +
                    "\n可供修改的属性有 姓名 性别 年龄 这三种\n";
        }
    }

    public static class SelectAct implements CommandLineHandler {
        @Override
        public void handle(String command, Employees employees) {
            LinkedList<String> segments = toList(command);
            TableInfo template = new Employee();
            if (segments.isEmpty()) {
                CommandLineHandler.println(TextTable.build(template, toTableInfo(employees.selectAll())));
            } else {
                if (segments.size() < 2)
                    throw new RuntimeException("缺少查询条件, 输入 help select 查看此功能的用法");

                String property = segments.removeFirst();
                Stream<Employee> employeeStream = employees.selectAll().stream();

                switch (property) {
                    case "编号": {
                        int id = AssertParser.parserInt(segments.removeFirst(), ErrorMsg.errId);
                        employeeStream = employeeStream.filter(emp -> emp.id == id);
                    } break;
                    case "年龄": {
                        int age = AssertParser.parserInt(segments.removeFirst(), ErrorMsg.errAge);
                        employeeStream = employeeStream.filter(emp -> emp.age == age);
                    } break;
                    case "性别": {
                        char sex = AssertParser.parserSex(segments.removeFirst(), ErrorMsg.errSex);
                        employeeStream = employeeStream.filter(emp -> emp.sex == sex);
                    } break;
                    case "姓名": {
                        String name = segments.removeFirst();
                        employeeStream = employeeStream.filter(emp -> emp.name.equals(name));
                    } break;
                    default:
                        throw new RuntimeException("查询失败, 未知属性 `" + property + "`");
                }

                List<TableInfo> selected = employeeStream.collect(Collectors.toList());
                CommandLineHandler.println(TextTable.build(template, selected));
                CommandLineHandler.println("满足条件的信息共有 " + selected.size() + " 条.\n");
            }
        }

        @Override
        public String help() {
            return
                    "\n查询员工信息\n" +
                    "此命令有两种用法\n" +
                    "用法一, 仅输入 select, 会输出所有员工的信息\n" +
                    "用法二, 按照条件查询员工的信息, 这种方式会筛选出满足条件的信息\n" +
                    "      select 条件 值\n" +
                    "示例: 查询年龄为 20 的员工的信息\n" +
                    "      select age 20\n\n" +
                    "示例: 查询编号为 1001 的员工的信息\n" +
                    "      select 编号 1001\n\n" +
                    "\n可供查询的属性有 编号 姓名 性别 年龄 这四种\n";
        }

        private Collection<TableInfo> toTableInfo(Collection<Employee> employeeCollection) {
            return employeeCollection.stream()
                    .map(item -> (TableInfo) item).collect(Collectors.toList());
        }
    }

}
